package com.arpa.wms.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.domain.entity.PartyGroupConfig;
import com.arpa.ntocc.common.mapper.PartyGroupConfigMapper;
import com.arpa.wms.common.util.OrderIdGeneratorUtil;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.ntocc.common.domain.entity.PartyGroupConfig;
import com.arpa.ntocc.common.mapper.PartyGroupConfigMapper;
import com.arpa.wms.common.util.OrderIdGeneratorUtil;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.consts.PropertyConst;
import com.arpa.wms.domain.entity.*;
import com.arpa.wms.domain.enums.DeliveryStatusEnum;
import com.arpa.wms.domain.enums.InventoryOperationMethodEnum;
import com.arpa.wms.domain.enums.InventoryRecordTypeEnum;
import com.arpa.wms.mapper.OutboundMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.qimen.api.DefaultQimenClient;
import com.qimen.api.QimenClient;
import com.qimen.api.request.DeliveryorderBatchconfirmRequest;
import com.qimen.api.request.DeliveryorderConfirmRequest;
import com.qimen.api.request.StockoutConfirmRequest;
import com.qimen.api.response.DeliveryorderBatchconfirmResponse;
import com.qimen.api.response.DeliveryorderConfirmResponse;
import com.qimen.api.response.StockoutConfirmResponse;
import com.taobao.api.ApiException;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.arpa.wms.domain.consts.NumConst.NUM_ZERO;

/**
 * @author liuxr
 * @date 2021年04月24日 13:30
 */
@Service
@Log4j2
public class ConfirmDeliveryUpdateDeliveryStatusService {

    @Value("${taobao.qimen.url}")
    private String url;
    @Value("${taobao.qimen.appkey}")
    private String appkey;
    @Value("${taobao.qimen.secret}")
    private String secret;

    private final IInventoryService iInventoryService;
    private final IDeliveryService iDeliveryService;
    private final IDeliveryItemService iDeliveryItemService;
    private final IDeliveryDistributionService iDeliveryDistributionService;
    @Autowired
    private InventoryOperationService inventoryOperationService;
    @Autowired
    private IInventoryRecordService iInventoryRecordService;
    @Resource
    private OutboundMapper outboundMapper;

    @Autowired
    private IOutboundService iOutboundService;

    @Autowired
    @Lazy
    private OutCheckService outCheckService;
    @Autowired
    private ShipmentCache shipmentCache;
    @Resource
    private PartyGroupConfigMapper partyGroupConfigMapper;

    public ConfirmDeliveryUpdateDeliveryStatusService(IInventoryService iInventoryService,
                                                      IDeliveryService iDeliveryService,
                                                      IDeliveryItemService iDeliveryItemService,
                                                      IDeliveryDistributionService iDeliveryDistributionService) {
        this.iInventoryService = iInventoryService;
        this.iDeliveryService = iDeliveryService;
        this.iDeliveryItemService = iDeliveryItemService;
        this.iDeliveryDistributionService = iDeliveryDistributionService;
    }

    /**
     * 更新订单状态，ERP回调失败，数据回滚
     *
     * @param delivery 订单信息
     * @author liuxr
     * @date 2021/4/23 14:46
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void updateInventory(Delivery delivery) {
        String code = delivery.getCode();
        //根据订单分配数量扣减临时库存
        List<DeliveryDistribution> deliveryDistributions = this.iDeliveryDistributionService.list(new LambdaQueryWrapper<DeliveryDistribution>()
                .eq(DeliveryDistribution::getDeliveryCode, code)
                .eq(DeliveryDistribution::getGroupCode, UserUtil.getBranchCode()));
        for (DeliveryDistribution deliveryDistribution : deliveryDistributions) {
            Inventory inventory = iInventoryService.getOne(new LambdaQueryWrapper<Inventory>()
                    .eq(Inventory::getCode, deliveryDistribution.getInventoryCode()));
            log.info("根据订单分配记录扣减临时库存。订单标识：{}；订单明细分配标识：{}；临时库存：{}",
                    delivery.getCode(),
                    deliveryDistribution.getCode(),
                    JSONUtil.toJsonStr(inventory));
            inventoryOperationService.operation(inventory, code,
                    deliveryDistribution.getDistributionQuantity(),
                    InventoryOperationMethodEnum.SUBTRACT,
                    InventoryRecordTypeEnum.OUTBOUND);
        }

        //回调奇门确认订单
        boolean bool = true;
        //判断如果是奇门订单，需要奇门确认
        String errorMsg = "";
        if (StrUtil.equals("qimen", delivery.getSourceType())) {
            try {
                List<DeliveryItem> deliveryItemLists = this.iDeliveryItemService.list(new LambdaQueryWrapper<DeliveryItem>()
                        .select(DeliveryItem::getGoodCode,
                                DeliveryItem::getPlanQuantity,
                                DeliveryItem::getActualPrice,
                                DeliveryItem::getSourceOrderCode,
                                DeliveryItem::getCode)
                        .eq(DeliveryItem::getDeliveryCode, delivery.getCode()));
                if(StrUtil.equalsAny(delivery.getOrderType(),"DBCK","CGTH")){
                    bool = stokcoutorderConfirm(delivery, deliveryItemLists);
                }else{
                    bool = deliveryorderConfirm(delivery, deliveryItemLists);
                }
            } catch (ApiException e) {
                log.error("回调奇门订单确认接口失败：", e);
                errorMsg = e.getErrMsg();
                bool = false;
                throw new ServiceException(e.getMessage());
            }
        }
        if (!bool) {
            throw new ServiceException(errorMsg);
        }
        //更新订单状态=出库完成,出库数量=复核数量;
        iDeliveryService.update(new UpdateWrapper<Delivery>().lambda()
                .eq(Delivery::getCode, code)
                .eq(Delivery::getIsCancel, NUM_ZERO)
                .eq(Delivery::getStatus, DeliveryStatusEnum.UN_DELIVERY.getValue())
                .set(Delivery::getStatus, DeliveryStatusEnum.DELIVERIED.getValue())
                .setSql(" send_num = recheck_quantity"));

        //更新订单明细出库数量
        iDeliveryItemService.update(new UpdateWrapper<DeliveryItem>().lambda()
                .eq(DeliveryItem::getDeliveryCode, code)
                .setSql(" outbound_quantity = plan_quantity"));

        //更新订单确认明细出库数量
        iDeliveryDistributionService.update(new UpdateWrapper<DeliveryDistribution>()
                .lambda()
                .eq(DeliveryDistribution::getDeliveryCode, code)
                .setSql(" outbound_quantity = distribution_quantity"));
    }


    /**
     * 回调奇门出库单确认接口
     *
     * @param delivery 订单信息
     */
    public boolean stokcoutorderConfirm(Delivery delivery,List<DeliveryItem> deliveryItemList) throws ApiException {
        String deliveryCode = delivery.getCode();
        String groupCode = delivery.getGroupCode();
        log.info("回调奇门出库单确认接口。订单号：{}", deliveryCode);
        StockoutConfirmRequest req = new StockoutConfirmRequest();
        req.setCustomerId(delivery.getCustomerId());
        req.setVersion("2.0");
        StockoutConfirmRequest.DeliveryOrder deliveryOrder = new StockoutConfirmRequest.DeliveryOrder();
        // 出库单号
        deliveryOrder.setDeliveryOrderCode(delivery.getDeliveryOrderCode());
        // 仓库编码
        deliveryOrder.setWarehouseCode(delivery.getWarehouseSerialNumber());
        // 出库单类型
        deliveryOrder.setOrderType(delivery.getOrderType());
        // 外部业务编码
        deliveryOrder.setOutBizCode(deliveryCode);
        Map<String,List<DeliveryDistribution>> deliveryDistributionMap = iDeliveryDistributionService.list(new LambdaQueryWrapper<DeliveryDistribution>()
                .eq(DeliveryDistribution::getDeliveryCode, deliveryCode)
                .eq(DeliveryDistribution::getGroupCode, groupCode)
        ).stream().collect(Collectors.groupingBy(DeliveryDistribution::getDeliveryItemCode));
        // 商品列表
        List<StockoutConfirmRequest.Item> items = new ArrayList<>();
        deliveryItemList.forEach(e -> {
            StockoutConfirmRequest.Item item = new StockoutConfirmRequest.Item();
            // 商品编码
            item.setItemCode(e.getGoodCode());
            // 包裹内该商品数量
            item.setQuantity((e.getPlanQuantity().intValue()) + "");
            items.add(item);
        });

        // 包裹信息
        List<StockoutConfirmRequest.Package> packages = new ArrayList<>();
        StockoutConfirmRequest.Package package1 = new StockoutConfirmRequest.Package();

        // 运单号
        if (StrUtil.equals(delivery.getCarrierType(), "express")) {
            package1.setExpressCode(delivery.getWaybillCode());
        } else {
            package1.setExpressCode("自提");
        }
        package1.setItems(items);
        packages.add(package1);
        req.setPackages(packages);
        //判断是否需要添加批次规则，例如万里牛由于解析批次数据异常，不能添加批次规则; true: 不添加批次规则；false : 添加批次规则
        boolean notAddBatchFlag = notAddBatch(delivery);

        // 单据列表
        List<StockoutConfirmRequest.OrderLine> orderLines = new ArrayList<>();
        deliveryItemList.forEach(e -> {
            StockoutConfirmRequest.OrderLine orderLine = new StockoutConfirmRequest.OrderLine();
            //添加批次规则
            if (!notAddBatchFlag) {
                stockoutAddBatchRule(deliveryDistributionMap,e,orderLine);
            }

            // 商品编码
            orderLine.setItemCode(e.getGoodCode());
            // 应发商品数量
//            orderLine.setPlanQty((e.getPlanQuantity().intValue()) + "");
            // 实发商品数量
            orderLine.setActualQty((e.getPlanQuantity().intValue()) + "");
//            orderLine.setActualPrice(e.getActualPrice().toString());
//            orderLine.setOrderSourceCode(e.getSourceOrderCode());
            orderLines.add(orderLine);
        });
        req.setDeliveryOrder(deliveryOrder);
        req.setOrderLines(orderLines);
        log.info("出库单号：【{}】的确认信息为,{}",delivery.getDeliveryOrderCode(),JSONUtil.toJsonStr(req));
        QimenClient client = new DefaultQimenClient(url, appkey, secret);
        log.info("回调奇门出库单确认接口。订单号：{}；请求报文信息：{}；", deliveryCode, JSONUtil.toJsonStr(req));
        StockoutConfirmResponse rsp = client.execute(req);
        log.info("回调奇门出库单确认接口。订单号：{}；返回信息：{}；", deliveryCode, JSONUtil.toJsonStr(rsp));

        if (StrUtil.equals(rsp.getFlag(), PropertyConst.SUCCESS)) {
            return true;
        } else {
            log.info("出库单奇门确认失败：{}",rsp.getMessage());
            throw new ApiException(rsp.getMessage());
        }
    }


    /**
     * 回调奇门订单确认接口
     *
     * @param delivery 订单信息
     */
    public boolean deliveryorderConfirm(Delivery delivery,List<DeliveryItem> deliveryItemList) throws ApiException {
        String deliveryCode = delivery.getCode();
        String groupCode = delivery.getGroupCode();
        log.info("回调奇门订单确认接口。订单号：{}", deliveryCode);
        DeliveryorderConfirmRequest req = new DeliveryorderConfirmRequest();
        req.setCustomerId(delivery.getCustomerId());
        req.setVersion("2.0");
        DeliveryorderConfirmRequest.DeliveryOrder deliveryOrder = new DeliveryorderConfirmRequest.DeliveryOrder();
        // 出库单号
        deliveryOrder.setDeliveryOrderCode(delivery.getDeliveryOrderCode());
        // 仓库编码
//        deliveryOrder.setWarehouseCode(delivery.getWarehouseCode());
        deliveryOrder.setWarehouseCode(delivery.getWarehouseSerialNumber());
        deliveryOrder.setOutBizCode(deliveryCode);
        // 出库单类型
        deliveryOrder.setOrderType(delivery.getOrderType());
        // 商品列表
        List<DeliveryorderConfirmRequest.Item> items = new ArrayList<>();

        Map<String,List<DeliveryDistribution>> deliveryDistributionMap = iDeliveryDistributionService.list(new LambdaQueryWrapper<DeliveryDistribution>()
                .eq(DeliveryDistribution::getDeliveryCode, deliveryCode)
                .eq(DeliveryDistribution::getGroupCode, groupCode)
        ).stream().collect(Collectors.groupingBy(DeliveryDistribution::getDeliveryItemCode));
        deliveryItemList.forEach(e -> {
            DeliveryorderConfirmRequest.Item item = new DeliveryorderConfirmRequest.Item();

            // 商品编码
            item.setItemCode(e.getGoodCode());
            // 包裹内该商品数量
            item.setQuantity(e.getPlanQuantity().longValue());
            items.add(item);
        });

        // 包裹信息
        List<DeliveryorderConfirmRequest.Package> packages = new ArrayList<>();
        DeliveryorderConfirmRequest.Package package1 = new DeliveryorderConfirmRequest.Package();
        // 物流公司编码
        package1.setLogisticsCode(delivery.getLogisticsCode());
        // 运单号
        if (StrUtil.equals(delivery.getCarrierType(), "express")) {
            package1.setExpressCode(delivery.getWaybillCode());
        } else {
            package1.setExpressCode("自提");
        }
        package1.setItems(items);
        //如果订单再wms拆分，则将拆分运单号传会erp
        if (StrUtil.isNotEmpty(delivery.getSplitWaybillCode())) {
            String[] splitWaybillCodes = delivery.getSplitWaybillCode().split(",");
            for (String splitWaybillCode : splitWaybillCodes) {
                DeliveryorderConfirmRequest.Package splitPackage = new DeliveryorderConfirmRequest.Package();
                BeanUtil.copyProperties(package1,splitPackage);
                splitPackage.setExpressCode(splitWaybillCode);
                splitPackage.setRemark("wms拆单");
                packages.add(splitPackage);
            }
        }
        packages.add(package1);

        req.setPackages(packages);
        deliveryOrder.setItems(items);

        //判断是否需要添加批次规则，例如万里牛由于解析批次数据异常，不能添加批次规则; true: 不添加批次规则；false : 添加批次规则
        boolean notAddBatchFlag = notAddBatch(delivery);

        // 单据列表
        List<DeliveryorderConfirmRequest.OrderLine> orderLines = new ArrayList<>();
        deliveryItemList.forEach(e -> {
            DeliveryorderConfirmRequest.OrderLine orderLine = new DeliveryorderConfirmRequest.OrderLine();
            //添加批次规则
            if (!notAddBatchFlag) {
                deliveryorderAddBatchRule(deliveryDistributionMap,e,orderLine);
            }

            // 商品编码
            orderLine.setItemCode(e.getGoodCode());
            // 应发商品数量
            orderLine.setPlanQty((e.getPlanQuantity().intValue()) + "");
            // 实发商品数量
            orderLine.setActualQty((e.getPlanQuantity().intValue()) + "");
            orderLine.setActualPrice(e.getActualPrice().toString());
            orderLine.setOrderSourceCode(e.getSourceOrderCode());

            orderLines.add(orderLine);
        });

        req.setDeliveryOrder(deliveryOrder);
        req.setOrderLines(orderLines);
        log.info("出库单号：【{}】的确认信息为,{}",delivery.getDeliveryOrderCode(),JSONUtil.toJsonStr(req));
        QimenClient client = new DefaultQimenClient(url, appkey, secret);
        log.info("回调奇门订单确认接口。订单号：{}；请求报文信息：{}；", deliveryCode, JSONUtil.toJsonStr(req));
        DeliveryorderConfirmResponse rsp = client.execute(req);
        log.info("回调奇门订单确认接口。订单号：{}；返回信息：{}；", deliveryCode, JSONUtil.toJsonStr(rsp));

        if (StrUtil.equals(rsp.getFlag(), PropertyConst.SUCCESS)) {
            return true;
        } else {
            log.error("销售订单奇门确认失败：{}",rsp.getMessage());
            throw new ApiException(rsp.getMessage());
        }
    }

    public boolean notAddBatch(Delivery delivery) {
        //delivery1只是为了获取入驻商编码
        Delivery delivery1 = iDeliveryService.getOne(new LambdaQueryWrapper<Delivery>()
                .select(Delivery::getShipmentCode)
                .eq(Delivery::getCode, delivery.getCode())
                .eq(Delivery::getGroupCode, delivery.getGroupCode())
        );
        String shipmentCode = delivery1.getShipmentCode();
        Map<String, Object> map = shipmentCache.get(shipmentCode);
        String erpCode = MapUtil.get(map, "erpCode", String.class);
        //查询出库确认不需要批次规则信息的erp编码,多个erp之间用逗号隔开
        PartyGroupConfig partyGroupConfig = partyGroupConfigMapper.selectOne(new QueryWrapper<PartyGroupConfig>().lambda()
                .eq(PartyGroupConfig::getType,"outconfirmWithoutBatches")
                .eq(PartyGroupConfig::getConfigKey,"erpCodeList")
                .eq(PartyGroupConfig::getBranchCode,delivery.getGroupCode())
        );

        if(partyGroupConfig != null && StringUtils.isNotBlank(partyGroupConfig.getConfigValue()) && StrUtil.isNotEmpty(erpCode)){
            return inErpCodeList(erpCode, partyGroupConfig.getConfigValue());
        }
        return false;
    }

    /**
     *
     * @param erpCode
     * @param erpCodeList
     * @return
     */
    private boolean inErpCodeList(String erpCode,String erpCodeList) {
        boolean flag=false;
        if(StringUtils.isNotEmpty(erpCodeList)){
            if(erpCodeList.indexOf(erpCode)>=0){
                flag=true;
            }
        }
        return flag;
    }
    /**
     * 添加批次规则
     *
     * @author rfwang
     * @date 2022/6/22 13:46
     */
    private void deliveryorderAddBatchRule(Map<String,List<DeliveryDistribution>> deliveryDistributionMap,DeliveryItem e,
                              DeliveryorderConfirmRequest.OrderLine orderLine) {
        List<DeliveryDistribution> deliveryDistributionList = MapUtil.get(deliveryDistributionMap, e.getCode(), List.class);

        List<DeliveryorderConfirmRequest.Batch> batchs = deliveryDistributionList.stream().map(distribution -> {
            DeliveryorderConfirmRequest.Batch batch = new DeliveryorderConfirmRequest.Batch();
            //对应库存批次,拓展2对应的商品批次
            if (StrUtil.isNotEmpty(distribution.getExtendTwo())) {
                batch.setBatchCode(distribution.getExtendTwo());
            } else {
                Inventory inventory = new Inventory();
                BeanUtil.copyProperties(distribution,inventory);
                String lot = OrderIdGeneratorUtil.generatorLot(inventory);
                batch.setBatchCode(lot);
            }

            if (null != distribution.getGmtManufacture()) {
                batch.setProductDate(distribution.getGmtManufacture().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }
            if (null != distribution.getGmtExpire()) {
                batch.setExpireDate(distribution.getGmtExpire().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }

            //对应生产批号
            batch.setProduceCode(distribution.getExtendOne());
            //默认正品
            batch.setInventoryType("ZP");
            batch.setActualQty(distribution.getPlanQuantity().toString());
            return batch;
        }).collect(Collectors.toList());
        orderLine.setBatchs(batchs);
        LocalDateTime gmtManufacture = e.getGmtManufacture();
        LocalDateTime getGmtExpire = e.getGmtExpire();
        if (null != gmtManufacture) {
            orderLine.setProductDate(gmtManufacture.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }
        if (null != getGmtExpire) {
            orderLine.setExpireDate(getGmtExpire.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }

        orderLine.setProductCode(deliveryDistributionList.get(NUM_ZERO).getExtendOne());
        orderLine.setBatchCode(e.getReceiveLot());
    }

    /**
     * 添加批次规则
     *
     * @author rfwang
     * @date 2022/6/22 13:46
     */
    private void stockoutAddBatchRule(Map<String,List<DeliveryDistribution>> deliveryDistributionMap,DeliveryItem e,
                                           StockoutConfirmRequest.OrderLine  orderLine) {
        List<DeliveryDistribution> deliveryDistributionList = MapUtil.get(deliveryDistributionMap, e.getCode(), List.class);

        List<StockoutConfirmRequest.Batch> batchs = deliveryDistributionList.stream().map(distribution -> {
            StockoutConfirmRequest.Batch batch = new StockoutConfirmRequest.Batch();
            //对应库存批次,拓展2对应的商品批次
            if (StrUtil.isNotEmpty(distribution.getExtendTwo())) {
                batch.setBatchCode(distribution.getExtendTwo());
            } else {
                Inventory inventory = new Inventory();
                BeanUtil.copyProperties(distribution,inventory);
                String lot = OrderIdGeneratorUtil.generatorLot(inventory);
                batch.setBatchCode(lot);
            }

            if (null != distribution.getGmtManufacture()) {
                batch.setProductDate(distribution.getGmtManufacture().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }
            if (null != distribution.getGmtExpire()) {
                batch.setExpireDate(distribution.getGmtExpire().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }

            //对应生成批号
            batch.setProduceCode(distribution.getExtendOne());
            //默认正品
            batch.setInventoryType("ZP");
            batch.setActualQty(distribution.getPlanQuantity().toString());
            return batch;
        }).collect(Collectors.toList());
        orderLine.setBatchs(batchs);
        LocalDateTime gmtManufacture = e.getGmtManufacture();
        LocalDateTime getGmtExpire = e.getGmtExpire();
        if (null != gmtManufacture) {
            orderLine.setProductDate(gmtManufacture.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }
        if (null != getGmtExpire) {
            orderLine.setExpireDate(getGmtExpire.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }

        orderLine.setProductCode(deliveryDistributionList.get(NUM_ZERO).getExtendOne());
        orderLine.setBatchCode(e.getReceiveLot());
    }

    /**
     * 异步奇门订单确认
     *
     * @author liuxr
     * @date 2021/5/24 12:14
     */
    @Async
    public Future<Boolean> asyncDeliveryorderConfirm(Delivery delivery,List<DeliveryItem> deliveryItemList) {
        try {
            if(StrUtil.equalsAny(delivery.getOrderType(),"DBCK","CGTH")){
                stokcoutorderConfirm(delivery, deliveryItemList);
            }else{
                deliveryorderConfirm(delivery, deliveryItemList);
            }
        } catch (ApiException e) {
            log.error("奇门订单确认失败：", e);
            throw new ServiceException("奇门订单回调失败,订单:" + delivery.getCode());
        }
        return new AsyncResult<>(true);
    }


    /**
     * 发货单批量确认
     *
     * @param deliverys 订单信息
     */
    public boolean deliveryorderBatchConfirm(List<Delivery> deliverys) {
        log.info("批量回调奇门订单确认接口 ");
        DeliveryorderBatchconfirmRequest req = new DeliveryorderBatchconfirmRequest();
        req.setCustomerId(deliverys.get(0).getCustomerId());
        req.setVersion("2.0");

        Set<String> deliveryCodes = deliverys.stream().map(Delivery::getCode).collect(Collectors.toSet());
        List<DeliveryItem> deliveryItemLists = this.iDeliveryItemService.list(new LambdaQueryWrapper<DeliveryItem>()
                .select(DeliveryItem::getDeliveryCode,
                        DeliveryItem::getGoodCode,
                        DeliveryItem::getPlanQuantity,
                        DeliveryItem::getActualPrice,
                        DeliveryItem::getSourceOrderCode)
                .in(DeliveryItem::getDeliveryCode, deliveryCodes));

        Map<String, List<DeliveryItem>> deliveryItemMap = deliveryItemLists.parallelStream().collect(Collectors.groupingBy(DeliveryItem::getDeliveryCode));

        List<DeliveryorderBatchconfirmRequest.Order> orders = deliverys.parallelStream().map(delivery -> {
            String warehouseCode = delivery.getWarehouseSerialNumber();
            DeliveryorderBatchconfirmRequest.Order order = new DeliveryorderBatchconfirmRequest.Order();
            order.setDeliveryOrderCode(delivery.getDeliveryOrderCode());
            order.setMessage(delivery.getDeliveryOrderCode());

            DeliveryorderBatchconfirmRequest.DeliveryOrder deliveryOrder = new DeliveryorderBatchconfirmRequest.DeliveryOrder();
            deliveryOrder.setDeliveryOrderCode(delivery.getDeliveryOrderCode());
            deliveryOrder.setOwnerCode(delivery.getShipmentCode());
            deliveryOrder.setDeliveryOrderId(delivery.getDeliveryOrderCode());
            deliveryOrder.setWarehouseCode(warehouseCode);
            deliveryOrder.setOutBizCode(delivery.getCode());
            // 出库单类型
            deliveryOrder.setOrderType(delivery.getOrderType());
            // 商品列表
            List<DeliveryItem> deliveryItemList = deliveryItemMap.get(delivery.getCode());
            List<DeliveryorderBatchconfirmRequest.Item> items = deliveryItemList.parallelStream().map(e -> {
                DeliveryorderBatchconfirmRequest.Item item = new DeliveryorderBatchconfirmRequest.Item();
                // 商品编码
                item.setItemCode(e.getGoodCode());
                // 包裹内该商品数量
                item.setQuantity(e.getPlanQuantity().longValue());

                // 应发商品数量
                item.setPlanQty((e.getPlanQuantity().intValue()) + "");
                // 实发商品数量
                item.setActualQty((e.getPlanQuantity().intValue()) + "");
                item.setWarehouseCode(warehouseCode);
                return item;
            }).collect(Collectors.toList());

            // 包裹信息
            List<DeliveryorderBatchconfirmRequest.Package> packages = new ArrayList<>();
            DeliveryorderBatchconfirmRequest.Package package1 = new DeliveryorderBatchconfirmRequest.Package();
            // 物流公司编码
            package1.setLogisticsCode(delivery.getLogisticsCode());
            // 运单号
            if (StrUtil.equals(delivery.getCarrierType(), "express")) {
                package1.setExpressCode(delivery.getWaybillCode());
            } else {
                package1.setExpressCode("自提");
            }
            package1.setItems(items);
            packages.add(package1);

            deliveryOrder.setItems(items);

            // 单据列表
            List<DeliveryorderBatchconfirmRequest.OrderLine> orderLines = new ArrayList<>();
            deliveryItemList.forEach(e -> {
                DeliveryorderBatchconfirmRequest.OrderLine orderLine = new DeliveryorderBatchconfirmRequest.OrderLine();
                // 商品编码
                orderLine.setItemCode(e.getGoodCode());
                // 应发商品数量
                orderLine.setPlanQty((e.getPlanQuantity().intValue()) + "");
                // 实发商品数量
                orderLine.setActualQty((e.getPlanQuantity().intValue()) + "");
                orderLine.setActualPrice(e.getActualPrice().toString());
                orderLine.setOrderSourceCode(e.getSourceOrderCode());

                orderLines.add(orderLine);
            });


            order.setDeliveryOrder(deliveryOrder);
            order.setPackages(packages);
            order.setOrderLines(orderLines);
            return order;
        }).collect(Collectors.toList());


        req.setOrders(orders);
        QimenClient client = new DefaultQimenClient(url, appkey, secret);
        DeliveryorderBatchconfirmResponse rsp = null;
        try {
            rsp = client.execute(req);
        } catch (ApiException e) {
            log.error("批量回调奇门订单确认接口异常。返回信息：{}；", e.getMessage());
            return false;
        }
        log.info("批量回调奇门订单确认接口。返回信息：{}", JSONUtil.toJsonStr(rsp));

        if (StrUtil.equals(rsp.getFlag(), PropertyConst.SUCCESS)) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 波次拣货确认，不需要复核操作时，自动更新出库数量及状态
     * @param delivery 订单信息
     * @param deliveryItemList 订单明细
     * @return
     */
    @Async
    public Future<Boolean> asyncAutoConfirm(Delivery delivery,List<DeliveryItem> deliveryItemList,String groupCode) {
        autoConfirm(delivery,deliveryItemList,groupCode);
        return new AsyncResult(true);
    }

    /**
     * 波次拣货确认，不需要复核操作时，自动更新出库数量及状态
     * 1、回调奇门订单确认接口
     * 2、更新订单发货数量及状态
     * 3、更新出库单发货数量
     * 4、更新临时库存
     * 5、按单调用中台扣费接口(出库正常完成调用扣费接口)
     * @param delivery
     * @param deliveryItemList
     * @param groupCode
     */
    public void autoConfirm(Delivery delivery,List<DeliveryItem> deliveryItemList,String groupCode){
//        boolean bool = true;  //待删除 or 测试待放开
        //todo 待放开
        boolean bool;
        try {
            if(StrUtil.equalsAny(delivery.getOrderType(),"DBCK","CGTH")){
                bool = stokcoutorderConfirm(delivery, deliveryItemList);
            }else{
                bool = deliveryorderConfirm(delivery,deliveryItemList);
            }
        } catch (Exception e) {
            log.info("奇门订单确认失败：", e);
            log.error("奇门订单确认失败：", e);
            bool = false;
        }
        log.info("拣货单跳过复核自动出库确认，订单【{}】奇门订单确认结果：{}",delivery.getCode(),bool);
        if (bool) {
            Set<String> codes = new HashSet<>();
            codes.add(delivery.getCode());
            //更新订单发货数量及状态
            iDeliveryService.autoUpdateStatusAndSendQuantity(codes,groupCode);
            log.info("拣货单跳过服务自动出库确认,更新订单发货数量及状态：订单【{}】",delivery.getCode());
            //查询出库单
            Outbound outbound = iOutboundService.getOne(new QueryWrapper<Outbound>().lambda()
                    .eq(Outbound::getDeliveryCode, delivery.getCode())
                    .eq(Outbound::getGroupCode,groupCode)
                    .eq(Outbound::getDeleted, "0"));
            //更新出库单发货数量
            outboundMapper.autoUpdateStatusAndSendQuantity(outbound.getCode(),groupCode);
            log.info("拣货单跳过服务自动出库确认,更新出库单发货数量及状态：订单【{}】",delivery.getCode());
            //获取所有已确认的订单分配信息
            List<DeliveryDistribution> deliveryDistributions = iDeliveryDistributionService.list(new LambdaQueryWrapper<DeliveryDistribution>()
                    .select(DeliveryDistribution::getCode,
                            DeliveryDistribution::getDeliveryCode,
                            DeliveryDistribution::getInventoryCode,
                            DeliveryDistribution::getOldInventoryCode,
                            DeliveryDistribution::getDistributionQuantity,
                            DeliveryDistribution::getRecheckRefundQuantity,
                            DeliveryDistribution::getRecheckQuantity,
                            DeliveryDistribution::getPickingQuantity,
                            DeliveryDistribution::getPickStockOutNum)
                    .eq(DeliveryDistribution::getDeliveryCode, delivery.getCode())
                    .eq(DeliveryDistribution::getGroupCode, groupCode));
            //更新临时库存
            inventoryOperationService.autoUpdateInventory(deliveryDistributions);
            log.info("拣货单跳过服务自动出库确认,更新临时库存：订单【{}】",delivery.getCode());

            //按单调用中台扣费接口(出库正常完成调用扣费接口)
            outbound.setWaybillCode(delivery.getWaybillCode());//面单号
            if(outbound.getType().equalsIgnoreCase("0")){ //只有销售出库扣费
                outCheckService.deductionByBill(outbound);
            }

        }else{
            log.error("奇门订单确认失败：{}", delivery.getCode());
        }
    }
}
